/*
 * Created by BAC IT Deustche Bank
 * User: Sergio Vasquez
 * Date: 5/12/2009
 * Time: 12:25 PM
 * 
 * Description:
 * 
 */
using IScheduler.Core.Properties;
using System;
using System.Text.RegularExpressions;

namespace IScheduler.Core.Schedule
{
   public struct Pattern
    {
        int lower, upper, step;

        public int LowerBound
        {
            get { return this.lower; }
        }

        public int UpperBound
        {
            get { return this.upper; }
        }

        public int StepSize
        {
            get { return this.step; }
        }

        public Pattern(int lowerBound, int upperBound, int stepSize)
        {
            if (lowerBound < 0 || stepSize < 0)
                throw new ArgumentException(Resources.SchedulePatternExceptionNegativeValueNotAllowed);

            if (upperBound < lowerBound)
                throw new ArgumentException(Resources.SchedulePatternExceptionEqualOrGreaterValue);

            this.lower = lowerBound;
            this.upper = upperBound;
            this.step = stepSize;
        }

        public int ComputeOffset(int current, int previous, int turn, bool force)
        {
            // If out of bounds, return the offset to reach the lower bound.
            if (current < this.lower) return this.lower - current;
            if (current > this.upper) return turn - current + this.lower;

            if (current < previous) current += turn;
            int offset = step - ((current - previous) % step);

            if (offset == step && !force) return 0;

            int next = current + offset;

            if (next < turn)
            {
                if (next <= this.upper) return offset;
                return turn - current + this.lower;
            }
            else
            {
                if (turn - 1 > this.upper) return turn - current + this.lower;
                return offset;
            }
        }

        static Regex PATTERN_PARSER = new Regex(@"^(((?<lower>\d+)(-(?<upper>\d+))?)|\*)(/(?<step>\d+))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);

        public static Pattern Parse(string text)
        {
            Match match = PATTERN_PARSER.Match(text);
            if (!match.Success) throw new FormatException(string.Format("The string {0} could not be parsed as a Pattern.", text));

            int lower, upper, step;
            lower = ParseGroup(match, "lower", -1);
            if (lower < 0)
            {
                lower = 0;
                upper = int.MaxValue;
            }
            else
            {
                upper = ParseGroup(match, "upper", lower);
            }
            step = ParseGroup(match, "step", 1);

            return new Pattern(lower, upper, step);
        }

        private static int ParseGroup(Match match, string groupName, int defaultValue)
        {
            Group group = match.Groups[groupName];
            return group.Success ? int.Parse(group.Value) : defaultValue;
        }
    }
}
